<?php
/**
 * Master.php class file.
 * @author wudg <544038230@qq.com>
 * @date 2020/10/24- 4:41 下午
 */

namespace console\components\daemons\cloud;
use Yii;
use swoole\Process;

class Master
{
    /**
     * 子进程列表
     * @var array
     */
    protected $processList = [];

    /**
     * 主循环定时器
     * @var integer
     */
    protected $timerId;

    protected $daemon = false;


    protected $processIdPath;

    /**
     * 构造方法
     * @param bool $daemon
     */
    public function __construct(bool $daemon =false)
    {

        $this->daemon = $daemon;
        $this->processIdPath = Yii::getAlias(Yii::$app->params['daemon']['cloud']['masterPidFilePath']);
        if($this->daemon == true) Process::daemon();
        swoole_set_process_name(Yii::$app->params['daemon']['cloud']['masterName']);
        file_put_contents($this->processIdPath, posix_getpid().PHP_EOL);
    }

    /**
     * 执行
     */
    public function run(): void
    {

        $this->createWorker(Yii::$app->params['daemon']['cloud']['workerNumber']);

//        Process::signal(SIGCHLD, [$this, 'handleForSIGCHLD']);
//        Process::signal(SIGTERM, [$this, 'handleForSIGTERM']);

        $this->timerId = swoole_timer_tick(6000, function($timerId, $params = NULL) {

        });

    }

    /**
     * 生成WORKER进程
     * @param int $number
     * @param bool $daemon
     */
    protected function createWorker(int $number): void
    {
        while ($number > 0)
        {
            $number--;

            $process = new Process(
                function(Process $process) use ($number) {
                    $worker = new Worker();
                    $worker->run();
                },
                false,
                0 //子进程内没有进程间通信需求
            );
            if($this->daemon == true) Process::daemon();

            $processId = $process->start();
            file_put_contents($this->processIdPath, $processId.PHP_EOL,FILE_APPEND);
            $this->processList[$processId] = $processId;
        }
    }

    /**
     * 子进程退出时信号响应方法
     * @param int $singalNumber
     */
    public function handleForSIGCHLD(int $singalNumber): void
    {
        while ($result = Process::wait(FALSE))
        {
            unset($this->processList[$result['pid']]);

            $this->createWorker(1);
        }
    }

    /**
     * 主进程退出时信号响应方法
     * @param int $singalNumber
     * @throws \yii\base\ExitException
     */
    public function handleForSIGTERM(int $singalNumber): void
    {
        $this->killChildren();

        swoole_timer_clear($this->timerId);

        while ($result = Process::wait(TRUE))
        {
            // do nothing
        }

        Yii::$app->end();
    }

    /**
     * 杀死子进程
     */
    protected function killChildren(): void
    {
        foreach ($this->processList as $processId)
        {
            Process::kill($processId, SIGTERM);
        }
    }
}
